import json
from datetime import datetime

from flask import current_app, jsonify
from flask import g
from flask import request
from flask import session

from ihome import db, sr
from ihome.models import Area, Facility, House, HouseImage, Order
from ihome.modules.api import api_blu
from ihome.utils import constants
from ihome.utils.common import check, file_upload
from ihome.utils.response_code import RET, error_map


# 获取城区信息
@api_blu.route('/areas', methods=['GET'])
def get_area_info():

    # 先尝试从缓存中获取数据
    try:
        resp_json = sr.get('area_info')
    except Exception as e:
        current_app.logger.error(e)
    else:
        if resp_json:
            current_app.logger.info('从redis中取出数据')
            print(resp_json)
            return resp_json, 200, {'Content-Type': 'application/json'}

    try:
        area_li = Area.query.all()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg=error_map[RET.DBERR])

    if not area_li:
        return jsonify(errno=RET.NODATA, errmsg=error_map[RET.NODATA])

    data = [area.to_dict() for area in area_li]
    resp_dict = {'errno': RET.OK, 'errmsg': error_map[RET.OK], 'data': data}
    resp_json = json.dumps(resp_dict)

    # 存入redis中
    try:
        sr.set('area_info', resp_json, constants.AREA_INFO_REDIS_EXPIRES)
    except Exception as e:
        current_app.logger.error(e)

    return resp_json, 200, {'Content-Type': 'application/json'}


# 我的房屋列表
@api_blu.route('/user/houses', methods=['GET'])
@check
def my_house_list():
    # 获取该用户所有房屋
    user = g.user
    houses = user.houses
    print(houses)
    # if not houses:
    #     return jsonify(errno=RET.NODATA, errmsg=error_map[RET.NODATA])
    # 组合数据
    houses = [house.to_basic_dict() for house in houses]
    return jsonify(errno=RET.OK, errmsg=error_map[RET.OK], data=houses)
    # return jsonify(errno=RET.OK, errmsg=error_map[RET.OK])


# 发布房源
@api_blu.route('/houses', methods=['POST'])
@check
def publish_house():
    # 接收参数
    user_id = g.user.id
    # 接受参数
    title = request.json.get('title')
    price = request.json.get('price')
    area_id = request.json.get('area_id')
    address = request.json.get('address')
    room_count = request.json.get('room_count')
    acreage = request.json.get('acreage')
    unit = request.json.get('unit')
    capacity = request.json.get('capacity')
    beds = request.json.get('beds')
    deposit = request.json.get('deposit')
    min_days = request.json.get('min_days')
    max_days = request.json.get('max_days')
    facilities = request.json.get('facility')
    print(facilities)
    # 校验参数
    if not all([title, price, area_id, address, room_count, acreage, unit, capacity, beds, deposit, min_days, max_days,
                facilities]):
        return jsonify(errno=RET.PARAMERR, errmsg=error_map[RET.PARAMERR])
    try:
        deposit = int(deposit)
        min_days = int(min_days)
        max_days = int(max_days)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.PARAMERR, errmsg=error_map[RET.PARAMERR])
    # 校验押金
    if deposit < 0:
        return jsonify(errno=RET.PARAMERR, errmsg=error_map[RET.PARAMERR])
    # 校验天数
    try:
        assert 0 < min_days < max_days
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.PARAMERR, errmsg=error_map[RET.PARAMERR])

    # 校验城区信息
    try:
        area = Area.query.get(area_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg=error_map[RET.PARAMERR])

    if not area:
        return jsonify(errno=RET.PARAMERR, errmsg=error_map[RET.PARAMERR])

    # 将数据存入数据库,除了设施

    house = House()
    house.user_id = user_id
    house.area_id = area_id
    house.title = title
    house.price = price
    house.address = address
    house.room_count = room_count
    house.acreage = acreage
    house.unit = unit
    house.capacity = capacity
    house.beds = beds
    house.deposit = deposit
    house.min_days = min_days
    house.max_days = max_days

    print(house)

    # 添加导数据库
    # db.session.add(house)
    # db.session.commit()
    facility_li = []
    for facility_id in facilities:
        facility_query = Facility.query.get(int(facility_id))
        print(facility_query)
        facility_li.append(facility_query)
    # print(facility_li)
    # 产生关联
    house.facilities.extend(facility_li)

    # db.session.add_all(facility_li)

    db.session.add(house)
    try:
        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
        db.session.rollback()

    # house.facilities = Facility.query.filter(Facility.id.in_(facilities)).all()
    # db.session.add_all()
    return jsonify(errno=RET.OK, errmsg=error_map[RET.OK], data={'house_id': house.id})


# 上传房屋图片
@api_blu.route('/houses/<int:house_id>/images', methods=['POST'])
@check
def upload_house_image(house_id):
    # 获取数据
    house_image = request.files.get('house_image')
    if not house_image:
        return jsonify(errno=RET.PARAMERR, errmsg=error_map[RET.PARAMERR])
    # 获取房子模型
    try:
        house = House.query.get(house_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg=error_map[RET.DBERR])
    if not house:
        return jsonify(errno=RET.NODATA, errmsg=error_map[RET.NODATA])

    # 上传图片
    image_bytes = house_image.read()
    try:
        file_name = file_upload(image_bytes)
    except BaseException as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.THIRDERR, errmsg=error_map[RET.THIRDERR])
    # todo:记录URL,这是一个对象,要声称记录,下面是错的
    # print(type(house.images.url))
    # house.images.url = file_name
    house_image = HouseImage()
    house_image.house_id = house.id
    house_image.url = file_name

    if not house.index_image_url:
        house.index_image_url = file_name

    db.session.add_all([house, house_image])
    data = {
        'url': constants.QINIU_DOMIN_PREFIX + file_name
    }
    return jsonify(errno=RET.OK, errmsg=error_map[RET.OK], data=data)


# 房屋详情
@api_blu.route('/houses/<int:house_id>', methods=['GET'])
def house_detail(house_id):
    user_id = session.get('user_id', -1)
    # if not user_id:
    #     user_id = -1


    # 查询房子信息
    # 先尝试从redis中获取信息
    resp_json = None
    try:
        resp_json = sr.get('house_info_%s' % house_id)
        current_app.logger.info('从redis中取出数据')
    except Exception as e:
        current_app.logger.error(e)

    if resp_json:
        return resp_json, 200, {'Content-Type': 'application/json'}
    print('='*50)


    try:
        house = House.query.get(house_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg=error_map[RET.DBERR])
    if not house:
        return jsonify(errno=RET.NODATA, errmsg=error_map[RET.NODATA])
    data = {
        'user_id': user_id,
        'house': house.to_full_dict()
    }

    # 存入redis数据库
    resp_dict = {'errno':RET.OK, 'errmsg': error_map[RET.OK], 'data': data}
    resp_json = json.dumps(resp_dict)
    try:
        sr.set('house_info_%s' % house_id, resp_json, constants.HOUSE_DETAIL_REDIS_EXPIRE_SECOND)
    except Exception as e:
        current_app.logger.error(e)

    # return jsonify(errno=RET.OK, errmsg=error_map[RET.OK], data=data)
    return resp_json, 200, {'Content-Type': 'application/json'}


# 房屋列表搜索
@api_blu.route('/houses', methods=['GET'])
def house_list():
    # 接受参数
    aid = request.args.get('aid')
    start_day = request.args.get('sd')
    end_day = request.args.get('ed')
    sort_key = request.args.get('sk')
    page = request.args.get('p', 1)

    try:
        page = int(page)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.PARAMERR, errmsg=error_map[RET.PARAMERR])

    try:
        start_day = None
        end_day = None
        if start_day:
            start_day = datetime.strptime(start_day, '%Y-%m_%d')

        if end_day:
            end_day = datetime.strptime(end_day, '%Y-%m_%d')

        if start_day and end_day:
            assert end_day > start_day
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.PARAMERR, errmsg=error_map[RET.PARAMERR])

    # todo:是否有区域id

    # 校验参数
    try:
        area = Area.query.get(aid)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.PARAMERR, errmsg=error_map[RET.PARAMERR])

    # 获取缓存数据
    redis_key = 'house_%s_%s_%s_%s' % (start_day, end_day, aid, sort_key)
    try:
        resp_json = sr.hget(redis_key, page)
    except Exception as e:
        current_app.logger.error(e)
    else:
        if resp_json:
            return resp_json, 200, {'Content-Type': 'application/json'}

    # 整合条件
    filter_list = []

    # todo:区域条件
    if aid:
        filter_list.append(House.area_id == aid)

    # todo:过滤已经销售的房子
    conflict_orders = None
    try:
        if start_day and end_day:
            conflict_orders = Order.query.filter(end_day >= Order.begin_date, start_day <= Order.end_date).all()
        elif start_day:
            conflict_orders = Order.query.filter(start_day <= Order.end_date).all()
        elif end_day:
            conflict_orders = Order.query.filter(end_day >= Order.begin_date).all()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg=error_map[RET.DBERR])

    # 冲突房子id
    if conflict_orders:
        conflict_house_id = [order.house_id for order in conflict_orders]
        # todo:不冲突的房子
        filter_list.append(House.id.notin_(conflict_house_id))

    # todo:根据筛选条件进行排序
    try:
        if sort_key == 'price-inc':
            house_query = House.query.filter(*filter_list).order_by(House.price.asc())
        elif sort_key == 'prict-des':
            house_query = House.query.filter(*filter_list).order_by(House.price.desc())
        elif sort_key == 'booking':
            house_query = House.query.filter(*filter_list).order_by(House.order_count.desc())
        else:
            house_query = House.query.filter(*filter_list).order_by(House.create_time.desc())
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg=error_map[RET.DBERR])
    # todo:分页
    paginate = house_query.paginate(page, constants.HOME_PAGE_MAX_HOUSES, False)

    # 获取当前页数据
    houses = paginate.items
    if not houses:
        return jsonify(errno=RET.NODATA, errmsg=error_map[RET.NODATA])
    house_list = [house.to_basic_dict() for house in houses]
    total_page = paginate.pages
    resp_dict = {'total_page': total_page, 'houses': house_list}
    resp_json = json.dumps({'data': resp_dict, 'errno': 0, 'errmsg': 'OK', })

    if page <= total_page:
        redis_key = 'house_%s_%s_%s_%s' % (start_day, end_day, aid, sort_key)
        # 存哈希
        try:
            # 创建redis管道兑对象
            pipline = sr.pipeline()

            # 开启多个语句的记录
            pipline.multi()

            pipline.hset(redis_key, page, resp_json)

            # 执行语句
            pipline.execute()
        except Exception as e:
            current_app.logger.error(e)

    return resp_json, 200, {'Content-Type': 'application/json'}


# 首页
@api_blu.route('/houses/index', methods=['GET'])
def index():
    resp_str = None
    # 先从缓存中获取
    try:
        resp_str = sr.get('index_house_info')
    except Exception as e:
        current_app.logger.error(e)
    if resp_str:
        current_app.logger.info('=========hit redis=======')
        return jsonify(errno=RET.OK, errmsg=error_map[RET.OK], data=eval(resp_str))

    # 查询预定数最多的五个房子及其照片
    houses = House.query.order_by(House.order_count.desc()).limit(constants.HOME_PAGE_MAX_HOUSES)
    print(houses)

    data = []
    if houses:
        for house in houses:
            if not house.index_image_url:
                continue
            data.append(
                {
                    'house_id': house.id,
                    'img_url': constants.QINIU_DOMIN_PREFIX + house.index_image_url,
                    'title': house.title
                }
            )

    # 存入缓存
    try:
        sr.set('index_house_info', data, constants.HOME_PAGE_DATA_REDIS_EXPIRES)
    except Exception as e:
        current_app.logger.error(e)

    return jsonify(errno=RET.OK, errmsg=error_map[RET.OK], data=data)